package com.cqrcb.cloud.config.redis.lock;

import com.cqrcb.cloud.config.redis.annotation.CustomLock;
import com.cqrcb.cloud.config.redis.constant.RedisTools;
import com.cqrcb.cloud.config.redis.el.ELUtil;
import com.cqrcb.cloud.config.redis.exception.LockException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.client.WriteRedisConnectionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;

/**
 * 分布式锁切面
 *
 * @author yangxueyong
 * @date 2021/06/01
 */
@Slf4j
@Aspect
public class LockAspect {
    @Autowired(required = false)
    private DistributedLock locker;

    @Autowired(required = false)
    private RedisTools redisTools;

    @Around("@within(lock) || @annotation(lock)")
    public Object aroundLock(ProceedingJoinPoint point, CustomLock lock) throws Throwable {
        if(!redisTools.getRedisAvailable()){
            return point.proceed();
        }
        if (lock == null) {
            // 获取类上的注解
            lock = point.getTarget().getClass().getDeclaredAnnotation(CustomLock.class);
        }
        String lockKey = lock.key();
        if (locker == null) {
            throw new LockException("DistributedLock is null");
        }
        if (StringUtils.isEmpty(lockKey)) {
            throw new LockException("lockKey is null");
        }

        if (lockKey.contains("#")) {
            MethodSignature methodSignature = (MethodSignature)point.getSignature();
            //获取方法参数值
            Object[] args = point.getArgs();
            lockKey = ELUtil.getValBySpEL(lockKey, methodSignature, args);
        }
        ZLock lockObj = null;
        try {
            try {
                //加锁
                if (lock.waitTime() > 0 || lock.isFailFast()) {
                    lockObj = locker.tryLock(lockKey, lock.waitTime(), lock.leaseTime(), lock.unit(), lock.isFair());
                } else {
                    lockObj = locker.lock(lockKey, lock.leaseTime(), lock.unit(), lock.isFair());
                }
            }catch (WriteRedisConnectionException e){
                redisTools.getAndSetRedisAvailable(false);
                log.warn("获取锁失败->{}",e.getMessage());
            }

            return point.proceed();

//            if (lockObj != null) {
//                return point.proceed();
//            } else {
//                throw new LockException("锁等待超时");
//            }
        } finally {
            if (lockObj != null) {
                locker.unlock(lockObj);
            }
        }
    }

}
